<template>
  <div>
    <div>平行光阴影计算</div>
    <div ref="webgl"></div>
  </div>
</template>
<script lang="ts" setup>
  import * as THREE from 'three';
  import { OrbitControls } from 'three/addons';
  import { onMounted, ref } from 'vue';

  const webgl: any = ref(null);
  let scene: any = null;
  let camera: any = null;
  let render: any = null;
  let controls: OrbitControls;
  onMounted(() => {
    init();
  });
  function init() {
    scene = new THREE.Scene();

    const width = window.innerWidth; //canvas画布宽度
    const height = window.innerHeight; //canvas画布高度

    const k = width / height; //canvas画布宽高比
    const s = 600; //控制left, right, top, bottom范围大小
    camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);
    camera.position.set(300, 300, 300);
    camera.lookAt(scene.position);
    render = new THREE.WebGLRenderer();
    // 背景颜色
    render.setClearColor('#f1f2f6');
    render.setSize(width, height);
    // 设置渲染器，允许光源阴影渲染
    render.shadowMap.enabled = true;
    render.shadowMap.type = THREE.PCFSoftShadowMap;

    webgl.value.appendChild(render.domElement);
    controls = new OrbitControls(camera, render.domElement);
    // const amLight = new THREE.AmbientLight(0xffffff);
    // scene.add(amLight);
    const helper = new THREE.AxesHelper(200);
    scene.add(helper);

    // 平面
    const geometry = new THREE.PlaneGeometry(1000, 1000);
    geometry.rotateX(Math.PI / 2);
    const material = new THREE.MeshBasicMaterial({ color: '#fff', side: THREE.DoubleSide });
    const plane = new THREE.Mesh(geometry, material);
    // 设置接收阴影的投影面
    plane.receiveShadow = true;

    scene.add(plane);
    // 球体
    const geometrySpher = new THREE.SphereGeometry(30, 32, 16);
    const materialSpher = new THREE.MeshLambertMaterial({
      color: 0xffff00,
      transparent: true,
      opacity: 0.9,
    });
    geometrySpher.translate(0, 30, 0);
    const sphereSpher = new THREE.Mesh(geometrySpher, materialSpher);
    // 设置产生投影的网格模型
    sphereSpher.castShadow = true;
    scene.add(sphereSpher);

    // 平行光
    const directionalLight = new THREE.DirectionalLight('#ea4300', 1);
    directionalLight.position.set(300, 200, 0);
    directionalLight.castShadow = true;

    const spotLightTarget = new THREE.Object3D(); //创建一个对象作为聚光灯的目标
    spotLightTarget.position.set(-30, 0, 0); //设置目标位置
    scene.add(spotLightTarget); //将目标对缘添加到场景中
    directionalLight.target = spotLightTarget; //设置聚光灯的目标为目标对象

    // 设置三维场景计算阴影的范围
    directionalLight.shadow.camera.left = -100;
    directionalLight.shadow.camera.right = 100;
    directionalLight.shadow.camera.top = 100;
    directionalLight.shadow.camera.bottom = -50;
    directionalLight.shadow.camera.near = 30;
    directionalLight.shadow.camera.far = 600;
    scene.add(directionalLight);
    const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight);

    scene.add(directionalLightHelper);
    // 查看平行光阴影相机属性
    console.log('阴影相机属性', directionalLight.shadow.camera);
    // 可视化平行光阴影对应的正投影相机对象
    const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
    scene.add(cameraHelper);

    renderFun();
  }

  function renderFun() {
    controls.update();
    // controls.update(); //update()函数内会执行camera.lookAt(controls.target)
    render.render(scene, camera);
    requestAnimationFrame(renderFun);
  }
</script>
<style lang=""></style>
